<?php
/**
 * pdk.class.php
 * 
 * PDK 核心类,并初始化框架的基本设置
 * 
 * @author lsl8966 <470663151@qq.com> 
 * @copyright Copyright (c) 2012 lsl8966 Software Studio
 * @link http://www.cnblogs.com/lsl8966
 * @version $Id: AutoLoad.class.php 1.0 2012-12-18 22:48:01Z lsl8966 $
 * @package include
 * @since 1.0
 */

if (!defined('IN_PDK')){
     exit();
 }
/**
 * 加载路由网址分析文件
 */
require_once LIBS_PATH . 'core/Router.class.php';

/**
 * pdk框架核心全局控制类

 * 用于初始化程序运行及完成基本设置
 * 
 * @author lsl <streen003@gmail.com> 
 * @version 1.0
 */
abstract class pdk{
    /**
     * 应用名称(app)
     * 
     * @var string 
     */
     public static $appname; //默认应用名称
    /**
     * 控制器(controller)
     * 
     * @var string 
     */
     public static $controller;
    
    /**
     * 动作(action)
     * 
     * @var string 
     */
     public static $action;
    
    /**
     * 对象注册表
     * 
     * @var array 
     */
     public static $_objects = array();
    
    /**
     * 载入的文件名(用于PHP函数include所加载过的)
     * 
     * @var array 
     */
     public static $_incFiles = array();
    
    /**
     * 项目运行函数
     * 
     * 供项目入口文件(index.php)所调用,用于启动框架程序运行
     * 
     * @access public 
     * @return object 
     */
     public static function run(){

        if(!PDK_DEBUG){
            error_reporting(0);
        }
         // 定义变量_app
        static $_app = array();
        /**
         * 加载配置文件列表
         */
         $config = include CONFIG_PATH . 'config.inc.php';
         foreach ($config as $value){
             if(is_file($value)){
                 config(include $value);
             }
         }
         // 分析URL,获取controller和action的名称
         $url_params = Router :: Request();
         if(isset($_GET['json']) || isset($_POST['json']) ){
             //接口路由支持
             $jPack = $_POST["json"]?$_POST["json"]:$_GET["json"];
             $jPack = stripcslashes($jPack);//过滤特殊字符
             $jsonObj = json_decode($jPack);
             $service = $jsonObj->service;
             $params = explode('.',$service);
             if(count($params)>2){
                 $url_params['app'] = $params[0];
                 $url_params['controller'] = $params[1];
                 $url_params['action'] = $params[2];
             } else {
                 $url_params['app'] = 'api';
                 $url_params['controller'] = $params[0];
                 $url_params['action'] = $params[1];
             }
         }
         $apps = config("DEFAULT_APPS");
         if(in_array($url_params['app'], $apps)){
             self :: $appname = $url_params['app'];
         }else{
             self :: $appname = $apps[0];
         }
         self :: $controller = $url_params['controller'];
         self :: $action = $url_params['action'];
        
         self :: setGlobal(); //设置全局变量
        
         $appId = self :: $controller . '_' . self :: $action;
         if (!isset($_app[$appId])){
             // 通过实例化及调用所实例化对象的方法,来完成controller中action页面的加载
             $app = self :: $appname;
             $controller = self :: $controller . 'Controller';
             $action = self :: $action . 'Action';
            
             // 加载基本文件:Base,Controller基类
            self :: loadFile(LIBS_PATH . 'core/Base.class.php');
             self :: loadFile(LIBS_PATH . 'core/Controller.class.php');

             // 加载当前要运行的controller文件
            if (is_file(CONTROLLER_DIR . $controller . '.class.php')){
                 // 当文件在controller根目录下存在时,直接加载.
                self :: loadFile(CONTROLLER_DIR . $controller . '.class.php');
             }else{
                 // 从controller的名称里获取子目录名称,注:controller文件的命名中下划线'_'相当于目录的'/'.
                $pos = strpos($controller, '_');
                 if ($pos !== false){
                     // 当$controller中含有'_'字符时
                     $childDirName = strtolower(substr($controller, 0, $pos));
                     $controllerFile = CONTROLLER_DIR . $childDirName . '/' . $controller . '.class.php';
                    
                     if (is_file($controllerFile)){
                         // 当子目录中所要加载的文件存在时
                        self :: loadFile($controllerFile);
                     }else{
                            // 当文件在子目录里没有找到时
                            self :: display404Error();
                         }
                 }else{
                         // 当controller名称中不含有'_'字符串时
                        self :: display404Error();
                 }
            }
            
             // 创建一个页面控制对象
             $appObject = new $controller();

             if (method_exists($controller, $action)){
                 $_app[$appId] = $appObject -> $action();
             }else{
                 // 所调用方法在所实例化的对象中不存在时.
                self :: display404Error();
             }
             }
         return $_app[$appId];
     }
    
    /**
     * 显示404错误提示
     * 
     * 当程序没有找到相关的页面信息时,或当前页面不存在.
     * 
     * @access public 
     * @return void 
     */
     private static function display404Error(){
         $apps = config("SERVICE_APPS");
         if(in_array(self :: $appname, $apps)){
             echo json_encode(array('code'=>404,'msg'=>'service not found'));
         }else{
             // 判断自定义404页面文件是否存在,若不存在则加载默认404页面
             is_file(VIEW_DIR . 'error/error404.html') ? self :: loadFile(VIEW_DIR . 'error/error404.html') : self :: loadFile(INCLUDE_PATH . 'views/html/error404.html');
         }
        // 既然提示404错误信息,程序继续执行下去也毫无意义,所以要终止(exit).
        exit();
     }
    
    /**
     * 获取当前运行的app名称
     * 
     * @example $appName = pdk::getAppName();
     * @access public 
     * @return string appname名称(字母全部小写)
     */
     public static function getAppName(){
        
         return strtolower(self :: $appname);
     }
    
    /**
     * 获取当前运行的controller名称
     * 
     * @example $controllerName = pdk::getControllerName();
     * @access public 
     * @return string controller名称(字母全部小写)
     */
     public static function getControllerName(){
        
         return strtolower(self :: $controller);
     }
    
    /**
     * 获取当前运行的action名称
     * 
     * @example $actionName = pdk::getActionName();
     * @access public 
     * @return string action名称(字母全部小写)
     */
     public static function getActionName(){
        
         return self :: $action;
     }
    
    /**
     * 返回唯一的实例(单例模式)
     * 
     * 程序开发中,model,module, widget, 或其它类在实例化的时候,将类名登记到pdk注册表数组($_objects)中,当程序再次实例化时,直接从注册表数组中返回所要的对象.
     * 若在注册表数组中没有查询到相关的实例化对象,则进行实例化,并将所实例化的对象登记在注册表数组中.此功能等同于类的单例模式.
     * 
     * 注:本方法只支持实例化无须参数的类.如$object = new pagelist(); 不支持实例化含有参数的.
     * 如:$object = new pgelist($total_list, $page);
     * 
     * <code>
     * $object = pdk::singleton('pagelist');
     * </code>
     * 
     * @access public 
     * @param string $className 要获取的对象的类名字
     * @return object 返回对象实例
     */
     public static function singleton($className){
        
         // 参数分析
        if (!$className){
             return false;
         }
         $key = trim($className);
         if (isset(self :: $_objects[$key])){
             return self :: $_objects[$key];
         }
         if(class_exists($className)){
             return self :: $_objects[$key] = new $className();
         } else {
             return null;
         }
     }
    
    /**
     * 静态加载文件(相当于PHP函数require_once)
     * 
     * include 以$fileName为名的php文件,如果加载了,这里将不再加载.
     * 
     * @param string $fileName 文件路径,注:含后缀名
     * @return boolean 
     */
     public static function loadFile($fileName){
        // 参数分析
        if (!$fileName){
             return false;
         }
         // 判断文件有没有加载过,加载过的直接返回true
        if (!isset(self :: $_incFiles[$fileName]) || !self :: $_incFiles[$fileName]){
             // 分析文件是不是真实存在,若文件不存在,则只能...
            // trackTrace();
            if (!is_file($fileName)){
                 // 当所要加载的文件不存在时,错误提示
                Controller :: halt('The file:' . $fileName . ' not found!');
             }
             include_once $fileName;
             self :: $_incFiles[$fileName] = true;
         }
        
         return self :: $_incFiles[$fileName];
     }
    
     public static function setGlobal(){
        /**
         * 项目controller目录的路径
         */
         if (!defined('CONTROLLER_DIR')){
             define('CONTROLLER_DIR', APPS_DIR . self :: $appname . '/controllers' . SEP);
         }
        /**
         * 项目model目录的路径
         */
         if (!defined('MODEL_DIR')){
             define('MODEL_DIR', APPS_DIR . self :: $appname . '/models' . SEP);
         }
        
        /**
         * 项目view目录的路径
         */
         if (!defined('VIEW_DIR')){
             define('VIEW_DIR', APPS_DIR . self :: $appname . '/views' . SEP);
         }
        
        /**
         * 项目config目录的路径
         */
         if (!defined('CONFIG_DIR')){
             define('CONFIG_DIR', APPS_DIR . self :: $appname . '/config' . SEP);
         }
        
        /**
         * 项目widget目录的路径
         */
         if (!defined('WIDGET_DIR')){
             define('WIDGET_DIR', APPS_DIR . self :: $appname . '/widgets' . SEP);
             }
        
        /**
         * 项目extension目录的路径
         */
         if (!defined('EXTENSION_DIR')){
             define('EXTENSION_DIR', APPS_DIR . self :: $appname . '/extensions' . SEP);
             }
        
        /**
         * 项目语言包文件存放目录的路径
         */
         if (!defined('LANG_DIR')){
             define('LANG_DIR', APPS_DIR . self :: $appname . '/language' . SEP);
         }
        
        /**
         * 项目资源文件
         */
         if(!defined('APP_SKIN')){
             define('APP_SKIN', SITE_PATH . 'app/' . self :: $appname . '/views/skin/') ;
         };

         /**
          * 项目资源文件
          */
         if(!defined('APP_VIEW_PATH')){
             define('APP_VIEW_PATH', SITE_PATH . 'app/' . self :: $appname . '/views/') ;
         };

         /**
          * 全局函数 
          */
         $filename = EXTENSION_DIR.'extents.func.php';
         if(file_exists($filename)){
             include_once $filename;
         }
    }

    /**
     * 页面结束时检查错误
     */
    public static  function shutdown($e = null) {
        if (isset($e) || (is_null($e = error_get_last()) === false)) {
            switch ($e['type']) {
                case E_ERROR:
                case E_PARSE:
                case E_CORE_ERROR:
                case E_COMPILE_ERROR:
                case E_USER_ERROR:
                    ob_end_clean();
                    $message = explode("\n", $e['message'], 3);
                    $e['message'] = $message[0];
                    $e['trace'] = isset($message[2]) ? $message[2] : null;
                    exit(json_encode($e));//TODO
                    break;
            }
        }
    }

    /**
     * 代理默认错误处理机制，return false时会继续使用默认机制
     *
     * @param int $errno
     * @param string $errstr
     * @param string $errfile
     * @param int $errline
     * @return boolean
     */
    public static  function error($errno, $errstr, $errfile, $errline) {
        switch ($errno) {
            case E_ERROR:
            case E_PARSE:
            case E_CORE_ERROR:
            case E_COMPILE_ERROR:
            case E_USER_ERROR:
                //TODO
                ob_end_clean();
                 exit($errstr . $errfile . " 第 $errline 行.");
                break;
            case E_NOTICE:
            case E_WARNING:
                break;
            default:
//                echo($errstr . $errfile . " 第 $errline 行.");
                //TODO
                break;
        }
        // Otherwise, use PHP's error handler
        return false;
    }
}

/**
 * 自动加载引导文件的加载
 */
include_once LIBS_PATH . 'core/AutoLoad.class.php';

/**
 * 调用SPL扩展,注册__autoload()函数.
 */
spl_autoload_register(array('AutoLoad', 'index'));
register_shutdown_function(array('pdk', 'shutdown'));
set_error_handler(array('pdk', 'error'));